package com.A21.GuoSai.demo.workflow_adjust.service;

import com.A21.GuoSai.demo.atom_adjust.service.AtomPojoService;
import com.A21.GuoSai.demo.service_entity.entity.atom.AtomServicePojo;
import com.A21.GuoSai.demo.service_entity.entity.atom.StaticVarPojo;
import com.A21.GuoSai.demo.service_entity.entity.workflow.DynamicVarValuePojo;
import com.A21.GuoSai.demo.service_entity.entity.workflow.ExpressionFlowPojo;
import com.A21.GuoSai.demo.service_entity.entity.workflow.StaticVarValuePojo;
import com.A21.GuoSai.demo.service_entity.entity.workflow.WorkFlowPojo;
import com.A21.GuoSai.demo.service_entity.utils.BpmnUtils;
import com.A21.GuoSai.demo.workflow_adjust.mapper.WorkFlowMapper;
import io.camunda.zeebe.client.api.command.DeployProcessCommandStep1;
import io.camunda.zeebe.model.bpmn.BpmnModelInstance;
import io.camunda.zeebe.model.bpmn.instance.ExtensionElements;
import io.camunda.zeebe.model.bpmn.instance.Task;
import io.camunda.zeebe.model.bpmn.instance.zeebe.ZeebeInput;
import io.camunda.zeebe.model.bpmn.instance.zeebe.ZeebeIoMapping;
import io.camunda.zeebe.spring.client.ZeebeClientLifecycle;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Slf4j
@Service
public class WorkFlowPojoService {

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;
    @Autowired
    private ZeebeClientLifecycle client;
    //工作流mapper
    @Autowired
    private WorkFlowMapper workFlowMapper;
    @Autowired
    private AtomPojoService atomPojoService;


    /**
     * 将字符流的bpmn文件存到数据库,同时将bpmn文件部署到Zeebe上
     * @param bpmn
     */
    @Transactional
    public void deployWorkFlow(String bpmn,String flowId,String flowName){
        try {
            //解析bpmn文件，得到一个modelInstance
            BpmnModelInstance modelInstance=BpmnUtils.getModelInstance(bpmn);
            insertExpressionFromBpmn(modelInstance,flowId);
            insertAllVariblesFromBpmn(modelInstance,flowId);
            DeployProcessCommandStep1 deployProcessCommand = client.newDeployCommand();
            deployProcessCommand.addResourceStringUtf8(bpmn,flowName).send().join();
        } catch (NullPointerException e) {
            System.out.println("bpmn文件为空！");
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("从bpmn文件读取变量出错！");
            e.printStackTrace();
        }
    }


    //解析bpmn文件，向数据库中写入其条件结点信息
    @Transactional
    void insertExpressionFromBpmn(BpmnModelInstance modelInstance, String flowId){
        //从这个modelInstance里面获取所有的条件结点信息，封装成一个List
        List<ExpressionFlowPojo> expressionFlowList=BpmnUtils.getAllExpressionFlows(modelInstance);
        expressionFlowList.forEach(expressionFlowPojo -> expressionFlowPojo.setFlowId(flowId));
        //批量插入expressionFlow
        SqlSession sqlSession= sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH,false);
        WorkFlowMapper wFMapper=sqlSession.getMapper(WorkFlowMapper.class);
//        List<EndEventPojo> endEventsList=BpmnUtils.getAllEndEvents(modelInstance);
//        endEventsList.forEach(wFMapper::insertEndEvent);
        expressionFlowList.forEach(wFMapper::insertExpressionFlow);
        sqlSession.commit();
    }


    //解析bpmn文件，像数据库中写入其变量信息
    @Transactional
    public void insertAllVariblesFromBpmn(BpmnModelInstance modelInstance, String flowId) throws Exception {
        List<StaticVarValuePojo> allStaticVarValue = this.getAllStaticVarValue(modelInstance);
        List<DynamicVarValuePojo> allDynamicVarValue = this.getAllDynamicVarValue(modelInstance);
        allStaticVarValue.forEach(staticVarValuePojo -> { staticVarValuePojo.setFlowId(flowId); });
        allDynamicVarValue.forEach(dynamicVarValuePojo -> {dynamicVarValuePojo.setFlowId(flowId);});
        //批量插入staticVarValue
        SqlSession sqlSession= sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH,false);
        WorkFlowMapper wFMapper=sqlSession.getMapper(WorkFlowMapper.class);
        allStaticVarValue.forEach(wFMapper::insertStaticVarValue);
        allDynamicVarValue.forEach(wFMapper::insertDynamicVarValue);
        sqlSession.commit();

        /*allDynamicVarValue.forEach(dynamicVarValuePojo -> {
            dynamicVarValuePojo.setFlowId(flowId);
            try {
                workFlowMapper.insertDynamicVarValue(dynamicVarValuePojo);
            } catch (Exception e) {
                System.out.println("工作流"+dynamicVarValuePojo.getFlowId()+"已存在动态变量:"+dynamicVarValuePojo.getD_name());
                e.printStackTrace();
            }
        });*/
    }


    //更新工作流信息
    @Transactional
    public void updateWorkFlow(WorkFlowPojo workFlowPojo) throws Exception {
        workFlowPojo.setChangeDate(new Date());
        //更新工作流的基本属性信息：flowId、Name、changeDate...
        workFlowMapper.updateWorkFlow(workFlowPojo);
        //更新已经部署在Zeebe上的工作流的条件结点、变量信息
        updateWorkFlowBpmn(workFlowPojo.getBpmn(),workFlowPojo.getFlowId(), workFlowPojo.getFlowName());
    }



    //更新已经部署在Zeebe上的工作流的条件结点、变量信息
    @Transactional
    public void updateWorkFlowBpmn(String bpmn, String flowId, String flowName) throws Exception {
        //解析bpmn文件，得到一个modelInstance
        BpmnModelInstance modelInstance=BpmnUtils.getModelInstance(bpmn);
        //删除原来bpmn文件的全部条件结点和变量
        workFlowMapper.deleteExpressionFlowByFlowId(flowId);
        workFlowMapper.deleteWorkFlowVars(flowId);
//        workFlowMapper.deleteWorkFlowStaVars(flowId);
        //重新解析bpmn文件，插入新的条件结点和变量信息
        insertExpressionFromBpmn(modelInstance,flowId);
        insertAllVariblesFromBpmn(modelInstance,flowId);
//        insertAllVariblesFromBpmn(modelInstance,flowId);
        DeployProcessCommandStep1 deployProcessCommand = client.newDeployCommand();
        deployProcessCommand.addResourceStringUtf8(bpmn,flowName).send().join();
    }



    /**
     * 保存工作流，保存了工作流自身的属性、条件结点以及变量的信息
     * @param workFlowPojo
     */
    @Transactional
    public void saveWorkerFlow(WorkFlowPojo workFlowPojo) throws Exception {
        WorkFlowPojo workFlow=workFlowMapper.getWorkerFlowByFlowId(workFlowPojo.getFlowId());
        //如果数据库中没有该工作流的信息，则添加相关信息
        if(workFlow == null){
            //workFlow表中插入工作流信息
            workFlowMapper.insertWorkFlow(workFlowPojo);
            //部署工作流，并且解析Bpmn文件，添加条件结点信息
            try {
                deployWorkFlow(workFlowPojo.getBpmn(),workFlowPojo.getFlowId(),workFlowPojo.getFlowName());
            } catch (Exception e) {
                log.error("工作流"+workFlowPojo.getFlowId()+"的部署出现错误:"+e.getMessage());
                throw e;
            }
        }
        //如果数据库已经有了该工作流，则修改条件信息
        else updateWorkFlow(workFlowPojo);
    }

    //查询工作流所有的静态变量值
    public List<AtomServicePojo> getWorkerFlowStaVarByFlowId(String flowId){
        //首先去除所有的原子服务的参数属性信息
//        List<AtomServicePojo> allAtomMessages = atomPojoService.getAllAtomMessages();
        //然后根据flowId取出该工作流已经配好的参数信息
        List<AtomServicePojo> workerFlowStaVarValueByFlowId = workFlowMapper.getWorkerFlowStaVarValueByFlowId(flowId);
        workerFlowStaVarValueByFlowId.forEach(
                workflow->{
                    workflow.getStaticVarList().forEach(
                            staVarValue->{staVarValue.setFlowId(flowId);}
                    );
                }
        );
        return workerFlowStaVarValueByFlowId;
    }

    public List<WorkFlowPojo> getAllServiceFlowList(){
        return workFlowMapper.getAllServiceFlowList();
    }
    //查询工作流的相关信息
    public WorkFlowPojo getWorkerFlowByFlowId(String flowId){
        return workFlowMapper.getWorkerFlowByFlowId(flowId);
    }
    //查询工作流的Bpmn文件信息
    public String getWorkerFlowBpmnByFlowId(String flowId){
        return workFlowMapper.getWorkerFlowBpmnByFlowId(flowId);
    }
    //查询工作流所有的静态变量值
    public List<AtomServicePojo> getWorkerFlowStaVarValueByFlowId( String flowId){
        return workFlowMapper.getWorkerFlowStaVarValueByFlowId(flowId);
    }
    //查询工作流所有的动态变量值
    public List<DynamicVarValuePojo> getWorkerFlowDynVarValueByFlowId( String flowId){
        return workFlowMapper.getWorkerFlowDynVarValueByFlowId(flowId);
    }

    //更改工作流的bpmn、changeDate、flowName还有flowDesc
    public void updateWorkFlowDesc(String flowId,String flowDesc){
        workFlowMapper.updateWorkFlowDesc(flowId, flowDesc);
    }

    //更改工作流的名称FlowName
    public void updateWorkFlowName(String flowId, String flowName){
        workFlowMapper.updateWorkFlowName(flowId, flowName);
    }

    //更改工作流的Bpmn文件FlowBpmn
    public void updateWorkFlowBpmn(String flowId, String flowBpmn){
        workFlowMapper.updateWorkFlowBpmn(flowId, flowBpmn);
    }

    //更改工作流的changeDate
    public void updateWorFlowChangeDate(String flowId, Date date){
        workFlowMapper.updateWorFlowChangeDate(flowId, date);
    }

    //删除数据库中工作流自身的信息、全部条件结点信息、全部变量信息
    public void deleteWorkFlow(String flowId){
        workFlowMapper.deleteWorkFlow(flowId);
    }

    //仅删除数据库中工作流的全部条件结点信息
    public void deleteExpressionFlowByFlowId(String flowId){
        workFlowMapper.deleteExpressionFlowByFlowId(flowId);
    }

    //仅删除数据库中与工作流相关的变量信息，会将staVarValue和dynVarValue都删除
    public void deleteWorkFlowParams( String flowId){
        workFlowMapper.deleteWorkFlowVars(flowId);
    }


    //根据工作流的flowId和ZeebeWorker的名字查询该worker的expressionFlow信息
    public List<String> getWorkerExpressionFlowMessage(String flowId, String workerName){
        return workFlowMapper.getWorkerExpressionFlowMessage(flowId, workerName);
    }


    /**
     * 从Bpmn文件中提取出所有的变量值，同时包括动态和静态变量
     * @param modelInstance
     * @return
     */
    @Transactional
    List<StaticVarValuePojo> getAllStaticVarValue(BpmnModelInstance modelInstance) throws Exception {
        List<StaticVarValuePojo> list=new ArrayList<>();

        Collection<Task> modelElementsByType = modelInstance.getModelElementsByType(Task.class);

        for(Task task:modelElementsByType){
            //获取task的name
            String taskName=task.getName();

            Collection<ExtensionElements> extensionElements = task.getChildElementsByType(ExtensionElements.class);
            for (ExtensionElements extensionElement:extensionElements) {
                Collection<ZeebeIoMapping> childElementsByType = extensionElement.getChildElementsByType(ZeebeIoMapping.class);
                for(ZeebeIoMapping ioMap:childElementsByType){
                    //获取所有的输入input
                    Collection<ZeebeInput> inputs = ioMap.getInputs();
                    for(ZeebeInput input:inputs){
                        String variableName=input.getTarget();
                        String variableValue=input.getSource().startsWith("=")? input.getSource().substring(1).trim() : input.getSource().trim();
                        //根据原子服务名和变量名获取原变量的详细信息
                        try {
                            StaticVarPojo staticVarPojo=atomPojoService.getStaticVarByName(taskName,variableName);
                            StaticVarValuePojo staticVarValuePojo=new StaticVarValuePojo();
                            staticVarValuePojo.setAtomName(taskName);
                            staticVarValuePojo.setAtomId(staticVarPojo.getAtomId());
                            staticVarValuePojo.setType(staticVarPojo.getType());
                            staticVarValuePojo.setS_name(variableName);
                            staticVarValuePojo.setValue(variableValue);

                            list.add(staticVarValuePojo);
                        } catch (Exception e) {
                            System.out.println("变量"+variableName+"在静态变量表中不存在！\n请检查变量名是否有误" +
                                    "或"+variableName+"为动态变量！！！");
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return list;
    }

    @Transactional
    List<DynamicVarValuePojo>  getAllDynamicVarValue(BpmnModelInstance modelInstance){
        List<Integer>atomIdlist=new ArrayList<>();
        Collection<Task> modelElementsByType = modelInstance.getModelElementsByType(Task.class);
        //获取bpmnModelInstance中所有原子服务的Id
        for(Task task:modelElementsByType) {
            //获取task的name
            String taskName=task.getName();
            atomIdlist.add(atomPojoService.getAtomIdByName(taskName));
        }
        return atomPojoService.getAtomDynamicVarByAtomIds(atomIdlist);
    }
}




